//
//  StageScene.swift
//  MixFruit
//
//  Created by remy on 2021/8/16.
//

class StageScene: SKScene {
    // 游戏状态检查时间
    let STATE_CHECK_TIME: TimeInterval = 0.8
    // 状态更新延迟时间,必须大于STATE_CHECK_TIME
    let STATE_UPDATE_DELAY: TimeInterval = 1.0
    // 当前水果下落前最大延迟时间
    let TIME_BEFORE_FALL: TimeInterval = 0.1
    // 当前水果下落后新水果生成前延迟时间
    let TIME_BEFORE_APPEAR: TimeInterval = 0.4
    // 水果出现时间
    let TIME_APPEAR: TimeInterval = 0.1
    private let WARNING_Y: CGFloat = UIScreen.height - 230.0
    private let GAMEOVER_Y: CGFloat = UIScreen.height - 80.0
    lazy var fruitWrap: SKSpriteNode = {
        let wrap = SKSpriteNode(color: UIColor(0xFBE8A6), size: UIScreen.size)
        wrap.anchorPoint = .zero
        wrap.position = .zero
        wrap.physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
        return wrap
    }()
    private lazy var scoreWrap: SKNode = {
        let score = SKNode()
        score.position = CGPoint(x: 30.0, y: UIScreen.height - 40.0)
        return score
    }()
    private lazy var redline: SKSpriteNode = {
        let redline = SKSpriteNode(imageNamed: "redline")
        redline.anchorPoint = CGPoint.zero
        redline.position = CGPoint(x: 0.0, y: GAMEOVER_Y)
        return redline
    }()
    // 至少预加载一次音频,否则会阻塞主线程
    var falldownAudio = SKAction.playSoundFileNamed("falldown", waitForCompletion: false)
    lazy var winAudio = SKAction.playSoundFileNamed("win", waitForCompletion: false)
    lazy var bombAudio = SKAction.playSoundFileNamed("bomb", waitForCompletion: false)
    lazy var fruitBox = FruitBox()
    var fallFruits: [SKSpriteNode] = []
    var nowFruit: SKSpriteNode?
    var isGameover: Bool = false
    private var updateTime: TimeInterval = 0.0
    var score: Int = 0 {
        didSet { updateScore() }
    }
    
    override init(size: CGSize) {
        super.init(size: size)
        physicsWorld.contactDelegate = self
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func didMove(to view: SKView) {
        view.ignoresSiblingOrder = true
        #if DEBUG
        view.showsDrawCount = true
        view.showsNodeCount = true
        view.showsFPS = true
        view.showsPhysics = true
//        view.showsQuadCount = true
//        view.showsFields = true
        #endif
        initScene()
        resetGame()
    }
    
    private func initScene() {
        self.removeAllChildren()
        // 水果区域
        self.addChild(fruitWrap)
        // 地下
        let underground = SKSpriteNode(color: UIColor(0x75553C), size: CGSize(width: UIScreen.width, height: (UIScreen.height / 5.0).rounded()))
        underground.anchorPoint = .zero
        underground.position = .zero
        self.addChild(underground)
        // 地面
        let ground = SKSpriteNode(color: UIColor(0xAC8959), size: CGSize(width: UIScreen.width, height: 10.0))
        ground.anchorPoint = .zero
        ground.position = CGPoint(x: 0.0, y: underground.height)
        let pb = SKPhysicsBody(edgeFrom: CGPoint(x: 0.0, y: 9.0), to: CGPoint(x: ground.width, y: 9.0))
        pb.categoryBitMask = 0xFF
        pb.contactTestBitMask = pb.categoryBitMask
        ground.physicsBody = pb
        self.addChild(ground)
        // 红线
        self.addChild(redline)
        // 分数
        self.addChild(scoreWrap)
    }
    
    func resetGame() {
        // 重置场景,数据
        self.childNode(withName: "end")?.removeFromParent()
        fruitWrap.removeAllChildren()
        fallFruits = []
        redline.isHidden = true
        redline.removeAllActions()
        score = 0
        isGameover = false
        // 初始化水果
        fruitBox.randomIndex = 0
        nowFruit = fruitBox.randomFruit()
        fruitWrap.addChild(nowFruit!)
    }
    
    private func updateScore() {
        scoreWrap.removeAllChildren()
        String(score).forEachEnumerated {
            let node = SKSpriteNode(imageNamed: "number/\($1)")
            node.position = CGPoint(x: 30.0 * CGFloat($0), y: 0.0)
            scoreWrap.addChild(node)
        }
    }
    
    private func checkGameStatus() {
        var status: Int = 0
        if !fallFruits.isEmpty {
            let max = fallFruits.count - 1
            for index in 0...max {
                let node = fallFruits[max - index]
                if node.frame.maxY > WARNING_Y {
                    status = 1
                    break
                }
            }
            if status == 1 {
                for index in 0...max {
                    let node = fallFruits[max - index]
                    if node.frame.maxY > GAMEOVER_Y {
                        status = 2
                        break
                    }
                }
            }
        }
        if status == 0 {
            redline.isHidden = true
            redline.removeAllActions()
        } else {
            if redline.isHidden {
                redline.isHidden = false
                redline.run(.repeatForever(.sequence([
                    .fadeIn(withDuration: 0.5),
                    .fadeOut(withDuration: 0.5)
                ])))
            }
            if status == 2 {
                if redline.action(forKey: "gameover") == nil {
                    redline.run(.sequence([
                        .wait(forDuration: STATE_UPDATE_DELAY),
                        .run {
                            self.gameover()
                        }
                    ]), withKey: "gameover")
                }
            } else {
                redline.removeAction(forKey: "gameover")
            }
        }
    }
    
    private func gameover() {
        guard !isGameover else { return }
        isGameover = true
        fruitWrap.children.forEach { $0.physicsBody = nil }
        let bestScore = max(UDShared[.bestScore] ?? 0, score)
        UDShared[.bestScore] = bestScore
        let wrap = SKSpriteNode(color: UIColor(0x000000, 0.4), size: UIScreen.size)
        wrap.anchorPoint = .zero
        wrap.position = .zero
        wrap.name = "end"
        self.addChild(wrap)
        let label = SKLabelNode(fontNamed: "AvenirNext-Medium")
        label.position = CGPoint(x: self.frame.midX, y: self.frame.midY + 70.0)
        label.verticalAlignmentMode = .center
        label.fontSize = 20.0
        label.fontColor = .white
        label.text = "\("now_score".localized): \(score)   \("best_score".localized): \(bestScore)"
        wrap.addChild(label)
        let gameover = SKSpriteNode(imageNamed: "gameover")
        gameover.position = CGPoint(x: self.frame.midX, y: self.frame.midY + 20.0)
        gameover.setScale(0.3)
        wrap.addChild(gameover)
        let restart = SKSpriteNode(imageNamed: "restart")
        restart.position = CGPoint(x: self.frame.midX, y: self.frame.midY - 20.0)
        restart.setScale(0.3)
        restart.name = "restart"
        wrap.addChild(restart)
    }
    
    override func update(_ currentTime: TimeInterval) {
        if currentTime > updateTime + STATE_CHECK_TIME {
            checkGameStatus()
            updateTime = currentTime
        }
    }
}

struct StageScene_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
